#include <linux/module.h>

#include "testing.h"
#include "context.h"


#define info(...) printk("info " __VA_ARGS__)

#include "prot.h"
#include "exceptions.h"
#include "handlers.h"

#include "result_str.h"


void handlers(void);
void end_handlers(void);

struct tester_data TESTER;


void *idt_page;
void init_contexts(void) {
  save_context (&(TESTER.linux_context));
  
  idt_page = (void *) get_zeroed_page (GFP_DMA);
	init_test_idt64(idt_page, (u64)handlers, 16);
  
  TESTER.test_context.idtr = make_test_idtr(idt_page);
  TESTER.test_context.cr3 = TESTER.linux_context.cr3;
}



void free_memory(void) {
  free_page((u64)idt_page);
}

void print_result (char *name) {
	print_row (name, &INTERRUPTS.int_info);
	memset (&INTERRUPTS.int_info, 0, sizeof(INTERRUPTS.int_info));
}



static int my_init(void)
{
  info("begin\n");
  init_contexts();
  info("contexts initialized\n");
  
  print_header();
  
  /** Devide Error */
  PREPARE_INTERRUPTS_HERE("DE");
  test_context();
  
  asm("xorl %ecx, %ecx\n\t"
      "divl %ecx\n\t");
  
  asm("DE:");
  linux_context();
  print_result ("DE");
  
  /** Global Protection error (clear LME)*/
  PREPARE_INTERRUPTS_HERE("lmeGP");
  test_context();
  
  asm("movl $0xC0000080, %ecx\n\t"
      "rdmsr\n\t"
      "andl $(~(1<<8)), %eax\n\t"
      "wrmsr\n\t");
  
  asm("lmeGP:");
  linux_context();
  print_result ("lmeGP");
  
  /** int 14 */
  PREPARE_INTERRUPTS_HERE("int14");
  test_context();
  
  asm("int $14");
  
  asm("int14:");
  linux_context();
  print_result ("int14");
  
  /** int 200 */
  PREPARE_INTERRUPTS_HERE("int200");
  test_context();
  
  asm("int $200");
  
  asm("int200:");
  linux_context();
  print_result ("int200");
  
  /** mov */
  PREPARE_INTERRUPTS_HERE("mov");
  test_context();
  
  asm("movl %eax, %eax");
  
  asm("mov:");
  linux_context();
  print_result ("mov");
  
  
  free_memory();
  info("finish\n");
  
  return 0;
}

static void my_exit(void) {
    info("exit\n");
}

module_init(my_init);
module_exit(my_exit);
